/**
 * 总结一下
 * 1、首先 promise 是一个类
 * 2、调用 promise 的时候，传入了一个函数，函数中有两个参数，成功 => resolve，失败 => reject
 * 3、调用其中一个函数的时候，其状态就不可更改了
 * 4、有一个 then 的方法
 * 5、then 里面有两个函数
 * 6、成功的回调函数和失败的回调函数
 */
// promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 1、首先 promise 是一个类
class MyPromise {
  // 2、调用 promise 的时候，传入了一个函数，函数中有两个参数，成功 => resolve，失败 => reject
  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch(e) {
      this.reject(e);
    }
  }
  // 3、定义一下他的状态
  status = PENDING;
  // 成功的返回值
  value = undefined;
  // 失败的返回值
  reject = undefined;
  // 存储成功的方法
  successCall = [];
  // 存储失败的方法
  errorCall = [];
  // 成功的函数，会传入一个 value
  resolve = value => {
    if (this.status !== PENDING) return;
    this.value = value;
    // 成功的函数改变他的状态
    this.status = FULFILLED;
    while(this.successCall.length) this.successCall.shift()();
  }
  // 失败的函数
  reject = reject => {
    if (this.status !== PENDING) return;
    this.reject = reject;
    // 失败状态
    this.status = REJECTED;
    while(this.errorCall.length) this.errorCall.shift()();
  }
  // 还有一个then的方法
  then(successCall, errorCall) {
    successCall = successCall ? successCall : value => value;
    errorCall = errorCall ? errorCall : error => { throw error };
    let myPromise2 = new MyPromise((resolve, reject) => {
      // 判断一下当前的状态
      if (this.status === FULFILLED) {
        setTimeout(()=> {
          try {
            let x = successCall(this.value);
            // resolve(x);
            // 如果返回的是一个promise对象呢
            resolvePromise(myPromise2, x, resolve, reject);
          } catch(e) {
            reject(e);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        // errorCall(this.reject);
        setTimeout(() => {
          try {
            let x = errorCall(this.reject);
            // 如果返回的是一个promise对象呢
            resolvePromise(myPromise2, x, resolve, reject);
          } catch(e) {
            reject(e);
          }
        }, 0);
      } else {
        // 异步调用处理
        this.successCall.push(() => {
          setTimeout(()=> {
            try {
              let x = successCall(this.value);
              // 如果返回的是一个promise对象呢
              resolvePromise(myPromise2, x, resolve, reject);
            } catch(e) {
              reject(e);
            }
          }, 0);
        });

        this.errorCall.push(() => {
          setTimeout(() => {
            try {
              let x = errorCall(this.reject);
              // 如果返回的是一个promise对象呢
              resolvePromise(myPromise2, x, resolve, reject);
            } catch(e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    return myPromise2;
  }
  finally(callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value);
    }, reason => {
      return MyPromise.resolve(callback()).then(() => { throw reason });
    });
  }
  catch(failCallback) {
    return this.then(undefined, failCallback);
  }
  // 静态方法添加 static
  static all(array) {
    let result = [];
    let count = 0;
    // 遍历这个数组
    // 写一个方法用来存储数据
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        count++;
        result[key] = value;
        if (count === array.length) {
          resolve(result);
        }
      }
      for(let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          current.then(value => addData(i, value), reason => reject(reason));
        } else {
          // 普通值
          addData(i, current);
        }
      }
    });
  }
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }
}

function resolvePromise(myPromise2, x, resolve, reject) {
  if (myPromise2 === x) {
    return reject(new TypeError('promise自己调用自己了'));
  }
  if (x instanceof MyPromise) {
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}

module.exports = MyPromise;
